package com.googlecode.dgwt.rebind;

import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.googlecode.dgwt.client.dojo.base.BrowserSensitive;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public class BrowserSensitiveGenerator extends Generator {


    public static final String USER_AGENT_PROPERTYNAME = "user.agent";
    
    
    @Override
    public String generate(TreeLogger logger, GeneratorContext context, final String targetName) throws UnableToCompleteException {
        
        TypeOracle typeOracle = context.getTypeOracle();
        String typeName = targetName;
        JClassType targetClass;
        String userAgent = null;

        while (true) {
            
            try {
                targetClass = typeOracle.getType(typeName);
            } catch (NotFoundException e) {
                logger.log(TreeLogger.ERROR, "No such type", e);
                throw new UnableToCompleteException();
            }
            
            BrowserSensitive.ReplaceWith replaceWith = targetClass.getAnnotation(BrowserSensitive.ReplaceWith.class);
            
            if (replaceWith != null) {
                try {
                    BrowserSensitive.WhenUserAgent selected = null;
                    BrowserSensitive.WhenUserAgent[] userAgentList = replaceWith.value();
                    
                    if (userAgent == null) {
                        userAgent = context.getPropertyOracle().getPropertyValue(logger, USER_AGENT_PROPERTYNAME);
                        
                        if (userAgent == null) {
                            logger.log(Type.ERROR, "Could not parse specified User Agent: NULL");
                            throw new UnableToCompleteException();
                        }
                    }
                    
                    if (userAgentList != null) {
                        for (BrowserSensitive.WhenUserAgent choice : userAgentList) {
                            
                            if (userAgent.matches("(?i)^"+choice.match().replace("\\v", "[\\d_]*")+"$")) {
                                selected = choice;                                
                            }
                        }
                    }
                    
                    if (selected != null) {
                        typeName = selected.type().getName().replace('$', '.');
                        continue;
                    }
                    
                } catch (BadPropertyValueException e) {
                    logger.log(Type.ERROR, "Could not parse specified User Agent");
                    throw new UnableToCompleteException();
                }
            }
            
            break;
        }
        
        return targetName.equals(typeName) ? null : typeName;
    }

}
